package com.wan.net.core.udp;

import com.wan.net.config.HostAndPort;
import com.wan.net.core.AbstractServer;
import com.wan.net.core.ServerType;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.epoll.Epoll;
import io.netty.channel.epoll.EpollDatagramChannel;
import io.netty.channel.epoll.EpollEventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioDatagramChannel;
import io.netty.handler.timeout.IdleStateHandler;
import io.netty.util.concurrent.DefaultThreadFactory;

import javax.annotation.Nullable;
/**
 * @author wwh
 * @date 2022/6/16 14:57
 */
public class UdpServer extends AbstractServer {

    public UdpServer(HostAndPort hostAndPort) {
        super(hostAndPort);
    }

    public UdpServer(HostAndPort hostAndPort, int idleTimeout) {
        super(hostAndPort, idleTimeout);
    }

    public UdpServer(HostAndPort hostAndPort, @Nullable ChannelHandler channelHandler) {
        super(hostAndPort, channelHandler);
    }

    public UdpServer(HostAndPort hostAndPort, int idleTimeout, @Nullable ChannelHandler channelHandler) {
        super(hostAndPort, idleTimeout, channelHandler);
    }

    @Override
    protected void channelChannelInitializer(ChannelPipeline pipeline) {
        pipeline.addLast(new UdpCodec());
    }

    @Override
    public void start() {
        int cpuNum = Runtime.getRuntime().availableProcessors();

        // 配置服务端nio线程组
        workerGroup = Epoll.isAvailable()
                ? new EpollEventLoopGroup(cpuNum * 2, new DefaultThreadFactory("netty-worker", true))
                : new NioEventLoopGroup(cpuNum * 2, new DefaultThreadFactory("netty-worker", true));

        Bootstrap bootstrap = new Bootstrap();
        bootstrap.group(workerGroup)
                .channel(Epoll.isAvailable() ? EpollDatagramChannel.class : NioDatagramChannel.class)
                .option(ChannelOption.SO_BROADCAST, true)
                .handler(new ChannelInitializer<Channel>() {
                    @Override
                    protected void initChannel(Channel channel) throws Exception {
                        ChannelPipeline pipeline = channel.pipeline();
                        //pipeline.addLast(new IdleStateHandler(0,0,idleTimeout));
                        channelChannelInitializer(pipeline);
                        pipeline.addLast(channelHandler);
                    }
                });

        // 异步
        channelFuture = bootstrap.bind(hostAndPort.getHost(), hostAndPort.getPort());
        channelFuture.syncUninterruptibly();
        channel = channelFuture.channel();
        SERVER_LIST.add(this);
        logger.info("{} started at [{}]", this.getClass().getSimpleName(), hostAndPort);
    }

    @Override
    public ServerType getServerType() {
        return ServerType.UDP;
    }
}
